
#pragma once

#include<muduo/base/Logging.h>
#include<muduo/net/Buffer.h>
#include<muduo/net/Endian.h>
#include<muduo/net/TcpConnection.h>

#include <boost/bind.hpp>
#include <boost/noncopyable.hpp>
#include <boost/function.hpp>

class LengthHeaderCodec:boost::noncopyable
{
public:
    typedef boost::function<void (const muduo::net::TcpConnectionPtr&,
                                  const muduo::string& message,
                                  muduo::Timestamp)> StringMessageCallback; //回调类型

    //构造函数
    explicit LengthHeaderCodec(const StringMessageCallback& cb)
            :messageCallback_(cb)
    {
    }

    //onMessage()和send()同前

    void onMessage(const muduo::net::TcpConnectionPtr& conn,
                   muduo::net::Buffer* buf,
                   muduo::Timestamp receiveTime)
    {
        while (buf->readableBytes() >= kHeaderLen) // kHeaderLen == 4
        {
            // FIXME: use Buffer::peekInt32()
            const void* data = buf->peek();//读取长度
            int32_t be32 = *static_cast<const int32_t*>(data); // SIGBUS
            const int32_t len = muduo::net::sockets::networkToHost32(be32);
            if (buf->readableBytes() >= len + kHeaderLen)
            {
                buf->retrieve(kHeaderLen);//回收数据
                muduo::string message(buf->peek(), len);//设置消息内容
                messageCallback_(conn, message, receiveTime);
                buf->retrieve(len);//回收所有数据
            }
            else
            {
                break;
            }
        }

    }
    void send(muduo::net::TcpConnection* conn,
              const muduo::StringPiece& message)
    {
        muduo::net::Buffer buf;
        buf.append(message.data(), message.size());//添加数据
        int32_t len = static_cast<int32_t>(message.size());
        //网络字节序是大端存储
        int32_t be32 = muduo::net::sockets::hostToNetwork32(len);//读取长度
        buf.prepend(&be32, sizeof be32);//添加长度
        conn->send(&buf);//发送数据
    }//
private:
    StringMessageCallback messageCallback_;
    const static size_t kHeaderLen = sizeof(int32_t);
};

